package satellite

import (
	"bytes"
	"fmt"
	"io"
	"sync"

	"github.com/pkg/errors"
)

var (
	MaxLengthError = errors.New("max length fail")
	ConnMissError  = errors.New("conn miss")
)

type VariProtocol struct {
	buffers       sync.Pool
	packet        sync.Pool
	headerPool    sync.Pool
	headLength    int
	maxLengthByte int
}

func NewVariProtocol(headLength int) *VariProtocol {
	// length：变长算法 最多4个字节
	maxLengthByte := headLength + 4 // 包含已经有的头
	protocol := &VariProtocol{
		buffers:       sync.Pool{},
		packet:        sync.Pool{},
		headerPool:    sync.Pool{},
		headLength:    headLength,
		maxLengthByte: maxLengthByte,
	}

	protocol.buffers.New = func() interface{} {
		return bytes.NewBuffer(make([]byte, 0, 1024))
	}
	protocol.packet.New = func() interface{} {
		return NewPacket()
	}
	protocol.headerPool.New = func() interface{} {
		return make([]byte, maxLengthByte)
	}
	return protocol
}

func (protocol *VariProtocol) Read(conn Conn) (*Packet, error) {
	if conn == nil || !conn.Connected() {
		return nil, ConnMissError
	}
	// 变长计算
	length := 0
	multiplier := 1

	var r io.Reader
	var err error
	var buffer *bytes.Buffer
	var pp *Packet
	var header []byte
	r, err = conn.Reader()
	if err != nil {
		return nil, err
	}
	buffer = protocol.buffers.Get().(*bytes.Buffer)
	pp = protocol.packet.Get().(*Packet)
	header = protocol.headerPool.Get().([]byte)
	pp.reset()
	buffer.Reset()

	if protocol.headLength > 0 {
		if _, err = r.Read(header[:protocol.headLength]); err != nil {
			goto Return
		}
		pp.Length = protocol.headLength
		pp.Head = header[:protocol.headLength]
	}
	//fmt.Println("<- ", pp.Head)
	pp.onClose(func() {
		protocol.buffers.Put(buffer)
		protocol.packet.Put(pp)
		protocol.headerPool.Put(header)
	})

	// 等待处理
	pp.onRead(func() error {
		var err error
		var b byte
		i := protocol.headLength
		for {
			i++
			if i > protocol.maxLengthByte {
				fmt.Println(MaxLengthError)
				break
			}
			if _, err = io.CopyN(buffer, r, 1); err != nil {
				if err == io.EOF {
					return err
				}
				//fmt.Println("read copy", err)
				break
			}
			b, err = buffer.ReadByte()
			if err != nil {
				if err == io.EOF {
					return err
				}
				//fmt.Println("buffer read", err)
				break
			}
			length += int(b&127) * multiplier
			multiplier *= 128
			if b&128 == 0 {
				break
			}
		}
		pp.Length = i - 1 + length

		//if protocol.headLength > 0 {
		//	fmt.Println("<- ", pp.Head, length)
		//}
		if length > 0 {
			_, err = io.CopyN(buffer, r, int64(length))
			if err != nil {
				if err == io.EOF {
					return err
				}
				//fmt.Println("body error:", err)
			}
		}

		pp.reader = buffer
		return err
	})

	//fmt.Println("<- ", pp.Code, compress, length)
	return pp, nil
Return:
	protocol.buffers.Put(buffer)
	protocol.packet.Put(pp)
	protocol.headerPool.Put(header)
	return nil, err
}

//func (protocol *VariProtocol) Read(conn Conn, handler func(*Packet)) error {
//	//var sid = ""
//	buffer := protocol.buffers.Get().(*bytes.Buffer)
//	pp := protocol.packet.Get().(*Packet)
//	header := protocol.headerPool.Get().([]byte)
//	// 变长计算
//	length := 0
//	multiplier := 1
//	stop := false
//
//	var r io.Reader
//	var err error
//	pp.CloseHandle = func() {
//		// 确保循环体关闭，底部按需收回reader
//		stop = true
//	}
//	for {
//		if stop {
//			goto Return
//		}
//		length = 0
//		multiplier = 1
//		//fmt.Println("<- ", h)
//		r, err = conn.Reader()
//		if err != nil {
//			goto Return
//		}
//		pp.reset()
//		buffer.Reset()
//
//		if protocol.headLength > 0 {
//			if _, err := r.Read(header[:protocol.headLength]); err != nil {
//				goto Return
//			}
//			pp.Length = protocol.headLength
//			pp.Head = header[:protocol.headLength]
//		}
//
//		// 等待处理
//		pp.ReadHandle = func() {
//			i := protocol.headLength
//			for {
//				i++
//				if i > protocol.maxLengthByte {
//					fmt.Println(MaxLengthError)
//					break
//				}
//				if _, err := io.CopyN(buffer, r, 1); err != nil {
//					fmt.Println(err)
//					break
//				}
//				b, err := buffer.ReadByte()
//				if err != nil {
//					fmt.Println(err)
//					break
//				}
//				length += int(b&127) * multiplier
//				multiplier *= 128
//				if b&128 == 0 {
//					break
//				}
//			}
//			pp.Length += i - 1 + length
//			buffer.Reset()
//
//			if length > 0 {
//				l, err := io.CopyN(buffer, r, int64(length))
//				if err != nil {
//					fmt.Println("body error:", err, l)
//				}
//			}
//
//			pp.Read = buffer
//		}
//
//		//fmt.Println("<- ", pp.Code, compress, length)
//		// 预先处理包， handler后读取read，报错
//		handler(pp)
//	}
//Return:

//	protocol.buffers.Put(buffer)
//	protocol.packet.Put(pp)
//	return err
//}

func (protocol *VariProtocol) Write(code []byte, conn Conn, handler func(writer io.Writer) error) (int, error) {
	if conn == nil || !conn.Connected() {
		return 0, ConnMissError
	}
	var err error

	var header []byte
	var length int
	var i int
	var count int
	var bodyL int64
	var w io.Writer

	buffer := protocol.buffers.Get().(*bytes.Buffer)
	buffer.Reset()
	if err := handler(buffer); err != nil {
		fmt.Println(err)
		goto Return
	}
	length = buffer.Len()

	header = protocol.headerPool.Get().([]byte)

	if protocol.headLength > 0 {
		for i, v := range code {
			header[i] = v
		}
	}

	i = protocol.headLength
	for length > 0 {
		if i > protocol.maxLengthByte {
			return 0, MaxLengthError
		}
		b := length % 128
		length = length / 128
		if length > 0 {
			b = b | 128
		}
		header[i] = byte(b) & 0xff
		i++
	}

	//if code != nil && buffer.Len() > 0 {
	//	fmt.Println("-> handle", code, buffer.Len(), header[:i])
	//}
	w, err = conn.StartWrite()
	if err != nil {
		goto Return
	}
	if w == nil {
		goto Return
	}
	count, err = w.Write(header[:i])
	if err != nil || count == 0 {
		if err != nil {

		}
		conn.EndWrite()
		goto Return
	}
	bodyL, err = buffer.WriteTo(w)
	if err != nil {
		conn.EndWrite()
		goto Return
	}
	conn.EndWrite()
Return:
	if header != nil {
		protocol.headerPool.Put(header)
	}
	protocol.buffers.Put(buffer)
	//fmt.Println("count ", count, body)
	return count + int(bodyL), err
}
